export function select (array, e) {
  var selected = array ? array.slice() : []
  var idx = selected.indexOf(e)
  if (idx >= 0) {
    selected.splice(idx, 1)
  } else {
    selected.push(e)
  }
  return selected
}

/**
 * Returns an array with arrays of the given size.
 *
 * @param array {Array} array to split
 * @param size {Integer} Size of every group
 */
export function chunk (array, size) {
  var lengtn = array.length
  var results = []

  for (var i = 0; i < lengtn; i += size) {
    var chunk = array.slice(i, i + size)
    // Do something if you want with the group
    results.push(chunk)
  }

  return results
}

export function unique (arr) {
  var unique = []
  for (var i = 0; i < arr.length; i++) {
    var current = arr[i]
    if (unique.indexOf(current) < 0) unique.push(current)
  }
  return unique
}

export function remove (arr, e) {
  var index = arr.indexOf(e)
  return arr.splice(index, 1)
}

/**
 * 判断(两个)数组是否有重复元素
 */
export function duplicates (left, right) {
  if (right) {
    for (let i = 0; i < right.length; i++) {
      if (left.indexOf(right[i]) > -1)
        return true
    }
    return false
  } else {
    var o = {}
    for (let i = 0; i < left.length; i++) {
      let val = left[i]
      if (o[val]) {
        return true
      }
      o[val] = 1
    }
    return false
  }
}

export function contains (arrays, e) {
  for (let i = 0; i < arrays.length; i++) {
    if (arrays[i].includes(e)) {
      return true
    }
  }
  return false
}

export function copy (o) {
  var out, key, val
  out = Array.isArray(o) ? [] : {}
  for (key in o) {
    if (o.hasOwnProperty(key)) {
      val = o[key]
      out[key] = (val !== null && typeof val === 'object') ? copy(val) : val
    }
  }
  return out
}

export function compare (a, b) {
  return a - b
}

export function reverse (a, b) {
  return b - a
}

export function random (min, max, length) {
  var numbers = []

  function _random (min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min
  }

  while (numbers.length < length) {
    var r = _random(min, max)
    if (numbers.includes(r)) {
      continue
    }
    numbers.push(r)
  }

  return numbers.sort(compare)
}

/**
 * Shuffles array in place.
 * @param {Array} array containing the items.
 */
export function shuffle (array) {
  var i = array.length,
      j = 0,
      temp

  while (i--) {
    j = Math.floor(Math.random() * (i + 1))
    // swap randomly chosen element with current element
    temp = array[i]
    array[i] = array[j]
    array[j] = temp
  }
  return array
}

export function cartesian (arrays, callback) {

  function recurse (arrays, callback, values) {
    var head = arrays[0]
    if (!head) {
      return
    }
    var len = head.length
    if (arrays.length == 1) {
      for (let i = 0, n = values.length; i < len; ++i) {
        values[n] = head[i]
        callback.call(this, values)
      }
    } else {
      for (let i = 0; i < len; ++i) {
        recurse(arrays.slice(1), callback, values.concat(head[i]))
      }
    }
  }

  recurse(arrays, callback, [])
}

/*
  Usage:
  cartesian([0,1], [0,1,2,3], [0,1,2]);
  To make the function take an array of arrays,
  just change the signature to function cartesian(arg)
  so that arg is a parameter instead of all arguments.
 */
export function eagerCartesian (arrays) {
  var results = [], max = arrays.length - 1

  function helper (arr, i) {
    for (var j = 0, l = arrays[i].length; j < l; j++) {
      var a = arr.slice(0) // clone arr
      a.push(arrays[i][j])
      if (i == max)
        results.push(a)
      else
        helper(a, i + 1)
    }
  }

  helper([], 0)
  return results
}

// combination([1, 2, 3, 4], 3);
export function combination (array, k, cb) {
  var combinations = []

  function run (level, start) {

    for (var i = start; i < array.length - k + level + 1; i++) {
      combinations[level] = array[i]

      if (level < k - 1) {
        run(level + 1, i + 1)
      } else {
        cb(combinations)
      }
    }
  }

  run(0, 0)
}

function permutation (array, callback) {
  // Do the actual permuation work on array[], starting at index
  function p (array, index, callback) {
    // Swap elements i1 and i2 in array a[]
    function swap (a, i1, i2) {
      var t = a[i1]
      a[i1] = a[i2]
      a[i2] = t
    }

    if (index == array.length - 1) {
      callback(array)
      return 1
    } else {
      var count = p(array, index + 1, callback)
      for (var i = index + 1; i < array.length; i++) {
        swap(array, i, index)
        count += p(array, index + 1, callback)
        swap(array, i, index)
      }
      return count
    }
  }

  if (!array || array.length == 0) {
    return 0
  }
  return p(array, 0, callback)
}

export function p (m, n) {
  var p = 1
  while (n-- > 0) p *= m--
  return p
}

export function c (m, n) {
  if (n > m) return 0
  return p(m, n) / p(n, n)
}
